/* Switch demo implementation using button and RGB LED
   
   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/

#include <sdkconfig.h>

#include <iot_button.h>
#include <esp_rmaker_core.h>
#include <esp_rmaker_standard_params.h> 

#include <app_reset.h>
#include <ws2812_led.h>
#include "app_priv.h"

#include "driver/ledc.h"
#include "esp_timer.h"

/* This is the button that is used for toggling the power */
#define BUTTON1_GPIO          GPIO_NUM_7
#define BUTTON1_ACTIVE_LEVEL  0

#define BUTTON2_GPIO          GPIO_NUM_1
#define BUTTON2_ACTIVE_LEVEL  0

#define LED_GPIO              GPIO_NUM_0  


/* This is the GPIO on which the power will be set */
#define OUTPUT_GPIO    GPIO_NUM_5
static bool g_power_state = false;

/* These values correspoind to H,S,V = 120,100,10 */
#define DEFAULT_RED     0
#define DEFAULT_GREEN   25
#define DEFAULT_BLUE    0

#define WIFI_RESET_BUTTON_TIMEOUT       3
#define FACTORY_RESET_BUTTON_TIMEOUT    10



#define LEDC_TIMER              LEDC_TIMER_0
#define LEDC_MODE               LEDC_LOW_SPEED_MODE
#define LEDC_OUTPUT_IO          (5) // Define the output GPIO  GPIO5
#define LEDC_CHANNEL            LEDC_CHANNEL_0
#define LEDC_DUTY_RES           LEDC_TIMER_11_BIT // Set duty resolution to 13 bits
#define LEDC_DUTY               (1331) //  65%, Set duty to 50%. (2 ** 13) * 50% = 4096
#define LEDC_DUTY_FULL          (2048) //  65%, Set duty to 50%. (2 ** 13) * 50% = 4096
#define LEDC_FREQUENCY          (25000) // Frequency in Hertz. Set frequency at 10 kHz

static esp_timer_handle_t oneshot_timer;

static void app_relay_init(void);
static void app_relay_pwm_init(void);
static void app_relay_set(bool state);
static void led_init(void);
static void app_indicator_init(void);
static void app_indicator_set(bool state);
static void set_power_state(bool target);


static void oneshot_timer_callback(void* arg)
{
    //set duty to 65%
    ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, LEDC_DUTY));
    ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL));
}

static void app_relay_init(void)
{
    app_relay_pwm_init();

    const esp_timer_create_args_t oneshot_timer_args = {
            .callback = &oneshot_timer_callback,
            .name = "one-shot"
    };
    ESP_ERROR_CHECK(esp_timer_create(&oneshot_timer_args, &oneshot_timer));
}

static void app_relay_pwm_init(void)
{
      // Prepare and then apply the LEDC PWM timer configuration
    ledc_timer_config_t ledc_timer = {
        .speed_mode       = LEDC_MODE,
        .timer_num        = LEDC_TIMER,
        .duty_resolution  = LEDC_DUTY_RES,
        .freq_hz          = LEDC_FREQUENCY,  // Set output frequency at 4 kHz
        .clk_cfg          = LEDC_AUTO_CLK
    };
    ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer));

    // Prepare and then apply the LEDC PWM channel configuration
    ledc_channel_config_t ledc_channel = {
        .speed_mode     = LEDC_MODE,
        .channel        = LEDC_CHANNEL,
        .timer_sel      = LEDC_TIMER,
        .intr_type      = LEDC_INTR_DISABLE,
        .gpio_num       = LEDC_OUTPUT_IO,
        .duty           = 0, // Set duty to 0%
        .hpoint         = 0
    };
    ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel));

}

static void app_relay_set(bool state)
{
    if(state){
         // Set duty to 100%
        ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, LEDC_DUTY_FULL));
        ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL));

        ESP_ERROR_CHECK(esp_timer_start_once(oneshot_timer, 200 * 1000)); //单位us
    }else{
        //set duty to 0%
        // ESP_ERROR_CHECK(ledc_stop(LEDC_MODE, LEDC_CHANNEL, 0));
        ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, 0));
        ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL));
    }
}

static void led_init(void)
{
    gpio_config_t io_conf = {
        .mode = GPIO_MODE_OUTPUT,
        .pull_up_en = 1,
    };
    io_conf.pin_bit_mask = ((uint64_t)1 << LED_GPIO);

    gpio_config(&io_conf);    
}

static void app_indicator_init(void)
{
    led_init();
    app_indicator_set(g_power_state);
}

static void app_indicator_set(bool state)
{
    bool led_state = !state;
    gpio_set_level(LED_GPIO, led_state);
}

static void set_power_state(bool target)
{
    // gpio_set_level(OUTPUT_GPIO, target);
    app_relay_set(target);
    app_indicator_set(target);
}


static void push_btn_cb(void *arg)
{
    bool new_state = !g_power_state;
    app_driver_set_state(new_state);
#ifdef CONFIG_EXAMPLE_ENABLE_TEST_NOTIFICATIONS
    /* This snippet has been added just to demonstrate how the APIs esp_rmaker_param_update_and_notify()
     * and esp_rmaker_raise_alert() can be used to trigger push notifications on the phone apps.
     * Normally, there should not be a need to use these APIs for such simple operations. Please check
     * API documentation for details.
     */
    if (new_state) {
        esp_rmaker_param_update_and_notify(
                esp_rmaker_device_get_param_by_name(switch_device, ESP_RMAKER_DEF_POWER_NAME),
                esp_rmaker_bool(new_state));
    } else {
        esp_rmaker_param_update_and_report(
                esp_rmaker_device_get_param_by_name(switch_device, ESP_RMAKER_DEF_POWER_NAME),
                esp_rmaker_bool(new_state));
        esp_rmaker_raise_alert("Switch was turned off");
    }
#else
    esp_rmaker_param_update_and_report(
            esp_rmaker_device_get_param_by_name(switch_device, ESP_RMAKER_DEF_POWER_NAME),
            esp_rmaker_bool(new_state));
#endif
}

void app_driver_init()
{
    button_handle_t btn1_handle = iot_button_create(BUTTON1_GPIO, BUTTON1_ACTIVE_LEVEL);
    if (btn1_handle) {
        /* Register a callback for a button tap (short press) event */
        iot_button_set_evt_cb(btn1_handle, BUTTON_CB_TAP, push_btn_cb, NULL);
        /* Register Wi-Fi reset and factory reset functionality on same button */
        app_reset_button_register(btn1_handle, WIFI_RESET_BUTTON_TIMEOUT, FACTORY_RESET_BUTTON_TIMEOUT);
    }

    button_handle_t btn2_handle = iot_button_create(BUTTON2_GPIO, BUTTON2_ACTIVE_LEVEL);
    if (btn2_handle) {
        iot_button_set_evt_cb(btn2_handle, BUTTON_CB_TAP, push_btn_cb, NULL);
    }


    // /* Configure power */
    // gpio_config_t io_conf = {
    //     .mode = GPIO_MODE_OUTPUT,
    //     .pull_up_en = 1,
    // };
    // io_conf.pin_bit_mask = ((uint64_t)1 << OUTPUT_GPIO);
    // /* Configure the GPIO */
    // gpio_config(&io_conf);

    app_relay_init();

    app_indicator_init();
}

int IRAM_ATTR app_driver_set_state(bool state)
{
    if(g_power_state != state) {
        g_power_state = state;
        set_power_state(g_power_state);
    }
    return ESP_OK;
}

bool app_driver_get_state(void)
{
    return g_power_state;
}
